import * as cc from 'cc'
import { Loger } from '../loger/Loger';
export class ResUtils {

    static loadBundle(bundleName: string) {
        return new Promise((resolve, reject) => {
            cc.assetManager.loadBundle(bundleName, (err, bundle) => {
                if (err) {
                    return reject(err);
                }
                resolve(bundle);
            });
        });
    }

    /**加载网络配置 */
    static loadOnlineCfg(url: string, type: string = ".json"): Promise<any> {
        return new Promise((resolve, reject) => {
            cc.assetManager.loadRemote(url, { ext: type }, function (err, res: cc.JsonAsset) {
                if (err) {
                    reject(err);
                } else {
                    if (res.json) {
                        cc.log("loadCfg===>>>", res.json);
                        resolve(res.json)
                    } else {
                        resolve(res)
                    }
                }
            })
        })
    }

    static getBundle(bundleName: string = "resources"): Promise<cc.AssetManager.Bundle> {
        return new Promise<cc.AssetManager.Bundle>(async (resolve, reject) => {
            let bundle = cc.assetManager.getBundle(bundleName);
            if (bundle) {
                resolve(bundle);
            }
            cc.assetManager.loadBundle(bundleName, (err, bundle) => {
                if (err) {
                    Loger.log("bundle不存在:", bundleName)
                    reject(err);
                    return;
                }
                resolve(bundle);
            })
        })

    }

    /**动态加载资源 */
    static loadRes<T>(path: string,type = null, bundleName: string = "resources"): Promise<T> {
        return new Promise<T>(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            bundle.load(path,type,(err: Error, res: any) => {
                    if (err) {
                        reject(err)
                    } else {
                        if (res.json) {
                            resolve(res.json)
                        } else {
                            resolve(res)
                        }
                    }
                })
        });
    }
    /**动态加载过的资源 */
    static getRes<T extends cc.Asset>(path: string,type = null, bundleName: string = "resources"): T {
        let bundle = cc.assetManager.getBundle(bundleName);
        if (bundle) {
            return bundle.get<T>(path,type);
        }
        return null;
    }

    /**预加载资源 */
    static preloadRes(path: string | string[], type: typeof cc.Asset, bundleName: string = "resources") {
        return new Promise<cc.Asset | cc.Asset[]>(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            bundle.preload(path, type, (err: Error, res: any[]) => {
                if (err) {
                    reject(err)
                } else {
                    resolve(res)
                }
            })
        });

    }

    /**根据path数组动态加载资源 */
    static loadResArray<T>(path: string[], bundleName: string = "resources"): Promise<T[]> {
        return new Promise<T[]>(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            bundle.load(path, (err: Error, res: any[]) => {
                if (err) {
                    reject(err)
                } else {
                    resolve(res)
                }
            })
        });
    }
    /**动态加载图片 */
    static loadSpriteFrame(path: string, bundleName: string = "resources"): Promise<cc.SpriteFrame> {
        return new Promise<cc.SpriteFrame>(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            bundle.load(`${path}/spriteFrame`, cc.SpriteFrame, (err: Error, res: any) => {
                if (err) {
                    reject(err)
                } else {
                    resolve(res)
                }
            })
        })
    }
    /**动态加载图片 */
    static loadTexture(path: string, bundleName: string = "resources"): Promise<cc.SpriteFrame> {
        return new Promise<cc.SpriteFrame>(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            bundle.load(`${path}/texture`, cc.SpriteFrame, (err: Error, res: any) => {
                if (err) {
                    reject(err)
                } else {
                    resolve(res)
                }
            })
        })
    }

    static loadSpineOrSpriteFrame(path: string, bundleName: string = "resources"): Promise<cc.SpriteFrame | cc.sp.SkeletonData> {
        return new Promise<cc.SpriteFrame | cc.sp.SkeletonData>(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            bundle.load(path, cc.sp.SkeletonData, (err: Error, res: any) => {
                if (err) {
                    bundle.load(`${path}/spriteFrame`, cc.SpriteFrame, (spErr: Error, res: any) => {
                        if (spErr) {
                            reject(spErr)
                        } else {
                            resolve(res)
                        }
                    })
                } else {
                    resolve(res)
                }
            })
        })
    }

    /**动态加载图片,找不到用默认图片替换 */
    static loadSpriteFrameWithDefault(path: string, bundleName: string = "resources"): Promise<cc.SpriteFrame> {
        return new Promise<cc.SpriteFrame>(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            bundle.load(`${path}/spriteFrame`, cc.SpriteFrame, (err: Error, res: cc.SpriteFrame) => {
                if (err) {
                    cc.resources.load("framework/texture/default_sprite/spriteFrame", cc.SpriteFrame, (err: Error, default_res: cc.SpriteFrame) => {
                        if (err) {
                            reject(err)
                        } else {
                            resolve(default_res)
                        }
                    })
                } else {
                    resolve(res)
                }
            })
        })
    }

    /**动态加载资源，加载失败也不报异常.返回空值*/
    static loadResNoError<T>(resource: string, bundleName: string = "resources", type = null): Promise<T> {
        return new Promise(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            bundle.load(resource, type, (err: Error, res: any) => {
                if (err) {
                    resolve(null)
                } else {
                    if (res.json) {
                        resolve(res.json)
                    } else {
                        resolve(res)
                    }
                }
            })
        });
    }

    /**释放资源 */
    static releaseRes(asset: cc.Asset) {
        cc.assetManager.releaseAsset(asset)
    }
    /**批量释放资源 */
    static releaseResArray(resources: cc.Asset[]) {
        resources.forEach(res => {
            cc.assetManager.releaseAsset(res);
        });
    }

    static releaseAsset(asset: cc.Asset) {
        cc.assetManager.releaseAsset(asset);
    }

    static releaseAssetArray(assets: cc.Asset[]) {
        for (let i = 0; i < assets.length; i++) {
            const asset = assets[i];
            cc.assetManager.releaseAsset(asset);
        }
    }

    static releaseByPath(path: string, bundleName: string = "resources") {
        var bundle = cc.assetManager.getBundle(bundleName);
        bundle?.release(path);
    }

    /**
     * 获取bundle里面的SpriteFrame
     * @param bundleName bundle名字
     * @param path 相对于bundle的路径
     * @returns 
     */
    static loadSpriteFrameInBundle(bundleName: string, path: string): Promise<cc.SpriteFrame> {
        return new Promise(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            // 加载 SpriteFrame
            bundle.load(`${path}/spriteFrame`, cc.SpriteFrame, (err, spriteFrame) => {
                if (err) {
                    reject(err)
                } else {
                    resolve(spriteFrame)
                }
            });
        });
    }

    /**
     * 加载bundel里面的场景,只加载场景，不运行
     * @param bundleName bundle名字
     * @param path 相对于bundle的路径
     * @returns 
     */
    static loadSceneInBundle(bundleName: string, path: string): Promise<cc.SceneAsset> {
        return new Promise(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            //只加载场景，不运行，手动调用director.runScene(scene)
            bundle.loadScene(path, (err, scene) => {
                if (err) {
                    reject(err)
                } else {
                    resolve(scene)
                }
            });
        });
    }

    /**
     * 加载bundle里面的预制体
     * @param bundleName bundle名字
     * @param path 相对于bundle的路径
     * @returns 
     */
    static loadPrefabInBundle(bundleName: string, path: string): Promise<cc.Prefab> {
        return new Promise(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            // 加载Prefab
            bundle.load(path, cc.Prefab, (err, prefab) => {
                if (err) {
                    reject(err)
                } else {
                    resolve(prefab)
                }
            });
        });
    }

    /**
     * 加载bundle里面的Texture2D
     * @param bundleName bundle名字
     * @param path 相对于bundle的路径
     * @returns 
     */
    static loadTextureInBundle(bundleName: string, path: string): Promise<cc.Texture2D> {
        return new Promise(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            // 加载 Texture2D
            bundle.load(`${path}/texture`, cc.Texture2D, (err, texture) => {
                if (err) {
                    reject(err)
                } else {
                    resolve(texture)
                }
            });
        });
    }

    /**
     * 加载bundle里面的声音资源
     * @param bundleName bundle名字
     * @param path 相对于bundle的路径
     * @returns 
     */
    static loadAudioInBundle(bundleName: string, path: string): Promise<cc.AudioClip> {
        return new Promise(async (resolve, reject) => {
            let bundle = await this.getBundle(bundleName)
            // 加载 Texture2D
            bundle.load(path, cc.AudioClip, (err, audioClip) => {
                if (err) {
                    reject(err)
                } else {
                    resolve(audioClip)
                }
            });
        });
    }

    /**
     * 加载远程图片SpriteFrame
     * @param url 图片网址
     * @param type 图片类型
     * @returns 
     */
    static loadRemoteSpriteFrame(url: string, type: string = ".png"): Promise<cc.SpriteFrame> {
        return new Promise<cc.SpriteFrame>((resolve, reject) => {
            let extObj = {};
            if (url.indexOf('.png') > 0 || url.indexOf('.jpg') > 0) {
                extObj = {};
            } else {
                extObj = { ext: type };
            }
            cc.assetManager.loadRemote<cc.ImageAsset>(url, extObj, (err, res: cc.ImageAsset) => {
                if (err) {
                    reject(err)
                } else {
                    const texture = new cc.Texture2D();
                    const spriteFrame = new cc.SpriteFrame();
                    texture.image = res;

                    spriteFrame.texture = texture;
                    spriteFrame.packable = false;
                    resolve(spriteFrame)
                }

            })
        })
    }

    /**
     * 加载远程音频
     * @param url 
     * @returns 
     */
    static loadRemoteAudio(url: string): Promise<cc.AudioClip> {
        return new Promise<cc.AudioClip>((resolve, reject) => {
            cc.assetManager.loadRemote<cc.AudioClip>(url, (err, res: cc.AudioClip) => {
                if (err) {
                    reject(err)
                } else {
                    resolve(res)
                }

            })
        })
    }

    /**
     * 加载远程文本
     * @param url 
     * @returns 
     */
    static loadRemoteTxt(url: string): Promise<cc.TextAsset> {
        return new Promise<cc.TextAsset>((resolve, reject) => {
            cc.assetManager.loadRemote<cc.TextAsset>(url, (err, res: cc.TextAsset) => {
                if (err) {
                    reject(err)
                } else {
                    resolve(res)
                }

            })
        })
    }

}